package com.dog.common.utils;


import com.dog.common.constant.Constant;
import com.dog.common.exception.CustomException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.Set;

/**
 * redis工具类
 * @author @Dog_Elder
 */
@Component
@Slf4j
public class JedisUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;
    public JedisUtil() {
    }

    /**
     * 获取redis实例
     * @return
     */
    public Jedis getJedis() {
        Jedis jedis = null;
        synchronized (Jedis.class) {
            try {
                jedis = getJedisPool().getResource();
            } finally {
                if (jedis != null) {
                    getJedisPool().returnBrokenResource(jedis);
                }
            }
        }
        return jedis;
    }

    public JedisPool getJedisPool() {
        JedisPool jedisPool = null;
        if (jedisPool == null) {
            synchronized (JedisPool.class) {
                if (jedisPool == null) {
                    jedisPool = applicationContext.getBean(JedisPool.class);
                }
            }
        }
        return jedisPool;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (JedisUtil.applicationContext == null) {
            JedisUtil.applicationContext = applicationContext; //初始化 spring applicationContext
        }
    }

    /**
     * 根据key查看是否存在
     *
     * @param key
     * @return
     */
    public boolean hasKey(String key) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.exists(key);
        }catch (Exception e){
            ////log.info("JedisUtil.hasKey异常："+e.getMessage());
            return false;
        }finally {
            disConnect(jedis);
        }
    }

    /**
     * 设置key -value 形式数据
     *
     * @param key
     * @param value
     * @return
     */
    public String set(String key, String value) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.set(key, value);
        }catch (Exception e){
            //log.info("JedisUtil.set(String key, String value)异常："+e.getMessage());
            return null;
        }finally {
            disConnect(jedis);
        }

    }

    /**
     * 设置 一个过期时间
     *
     * @param key
     * @param value
     * @param timeOut 单位秒
     * @return
     */
    public String set(String key, String value, int timeOut) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.setex(key, timeOut, value);
        }catch (Exception e){
            //log.info("JedisUtil.set(String key, String value, int timeOut)异常："+e.getMessage());
            return null;
        }finally {
            disConnect(jedis);
        }
    }

    /**
     * 根据key获取value
     *
     * @param key
     * @return
     */
    public String getByKey(String key) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.get(key);
        }catch (Exception e){
            //log.info("JedisUtil.getByKey(String key)异常："+e.getMessage());
            return null;
        }finally {
            disConnect(jedis);
        }
    }

    /**
     * 根据通配符获取所有匹配的key
     * @param pattern
     * @return
     */
    public Set<String> getKesByPattern(String pattern) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.keys(pattern);
        }catch (Exception e){
            //log.info("JedisUtil.getKesByPattern(String pattern)异常："+e.getMessage());
            return null;
        }finally {
            disConnect(jedis);
        }
    }

    /**
     * 根据key删除
     * @param key
     */
    public void delByKey(String key) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            if (jedis.exists(key)) {
                jedis.del(key);
            }
        }catch (Exception e){
            //log.info("JedisUtil.delByKey(String key)异常："+e.getMessage());
        }finally {
            disConnect(jedis);
        }
    }

    /**
     * 根据key获取过期时间
     *
     * @param key
     * @return
     */
    public long getTimeOutByKey(String key) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.ttl(key);
        }catch (Exception e){
            //log.info("JedisUtil.getTimeOutByKey(String key)异常："+e.getMessage());
            return 0;
        }finally {
            disConnect(jedis);
        }

    }

    /**
     * 清空数据 【慎用啊！】
     */
    public void flushDB(){
        Jedis jedis=null;
        try{
            jedis = getJedis();
            jedis.flushDB();
        }catch (Exception e){
            //log.info("JedisUtil.flushDB() 异常："+e.getMessage());
        }finally {
            disConnect(jedis);
        }

    }

    /**
     * 刷新过期时间
     * @param key
     * @param timeOut
     * @return
     */
    public long refreshLiveTime(String key, int timeOut) {
        Jedis jedis=null;
        try{
            jedis = getJedis();
            return jedis.expire(key, timeOut);
        }catch (Exception e){
            //log.info("JedisUtil.hasKey异常："+e.getMessage());
            return -1;
        }finally {
            disConnect(jedis);
        }
    }

    /**
     * 释放资源
     */
    public void disConnect(Jedis jedis) {
        if (jedis!=null){
            jedis.disconnect();
//            jedis.close();
        }
    }



    /**
     * 静态注入JedisPool连接池
     * 本来是正常注入JedisUtil，可以在Controller和Service层使用，但是重写Shiro的CustomCache无法注入JedisUtil
     * 现在改为静态注入JedisPool连接池，JedisUtil直接调用静态方法即可
     * https://blog.csdn.net/W_Z_W_888/article/details/79979103
     */
    private static JedisPool jedisPool;
    @Autowired
    public void setJedisPool(JedisPool jedisPool) {
        JedisUtil.jedisPool = jedisPool;
    }

    /**
     * 获取Jedis实例
     * @param
     * @return redis.clients.jedis.Jedis
     * @author dog_E
     * @date 2018/9/4 15:47
     */
    public static synchronized Jedis getResource() {
        try {
            if (jedisPool != null) {
                return jedisPool.getResource();
            } else {
                return null;
            }
        } catch (Exception e) {
            throw new CustomException("获取Jedis资源异常:" + e.getMessage());
        }
    }

    /**
     * 释放Jedis资源
     * @param
     * @return void
     * @author dog_E
     * @date 2018/9/5 9:16
     */
    public static void closePool() {
        try {
            jedisPool.close();
        } catch (Exception e) {
            throw new CustomException("释放Jedis资源异常:" + e.getMessage());
        }
    }

    /**
     * 获取redis键值-object
     * @param key
     * @return java.lang.Object
     * @author dog_E
     * @date 2018/9/4 15:47
     */
    public static Object getObject(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            String bytes = jedis.get(key);
            if (SUtils.isNotBlank(bytes)) {
                return bytes;
            }
        } catch (Exception e) {
            throw new CustomException("获取Redis键值getObject方法异常:key=" + key + " cause=" + e.getMessage());
        }
        return null;
    }

    /**
     * 设置redis键值-object
     * @param key
     * @param value
     * @return java.lang.String
     * @author dog_E
     * @date 2018/9/4 15:49
     */
    public static String setObject(String key, Object value) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.set(key.getBytes(), SerializableUtil.serializable(value));
        } catch (Exception e) {
            throw new CustomException("设置Redis键值setObject方法异常:key=" + key + " value=" + value + " cause=" + e.getMessage());
        }
    }

    /**
     * 设置redis键值-object-expiretime
     * @param key
     * @param value
     * @param expiretime
     * @return java.lang.String
     * @author dog_E
     * @date 2018/9/4 15:50
     */
    public static String setObject(String key, Object value, int expiretime) {
        String result;
        try (Jedis jedis = jedisPool.getResource()) {
            result = jedis.set(key, String.valueOf(value));
            if (Constant.RedisPrefixConstant.OK.equals(result)) {
                jedis.expire(key.getBytes(), expiretime);
            }
            return result;
        } catch (Exception e) {
            throw new CustomException("设置Redis键值setObject方法异常:key=" + key + " value=" + value + " cause=" + e.getMessage());
        }
    }

    /**
     * 获取redis键值-Json
     * @param key
     * @return java.lang.Object
     * @author dog_E
     * @date 2018/9/4 15:47
     */
    public static String getJson(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.get(key);
        } catch (Exception e) {
            throw new CustomException("获取Redis键值getJson方法异常:key=" + key + " cause=" + e.getMessage());
        }
    }

    /**
     * 设置redis键值-Json
     * @param key
     * @param value
     * @return java.lang.String
     * @author dog_E
     * @date 2018/9/4 15:49
     */
    public static String setJson(String key, String value) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.set(key, value);
        } catch (Exception e) {
            throw new CustomException("设置Redis键值setJson方法异常:key=" + key + " value=" + value + " cause=" + e.getMessage());
        }
    }

    /**
     * 设置redis键值-Json-expiretime
     * @param key
     * @param value
     * @param expiretime
     * @return java.lang.String
     * @author dog_E
     * @date 2018/9/4 15:50
     */
    public static String setJson(String key, String value, int expiretime) {
        String result;
        try (Jedis jedis = jedisPool.getResource()) {
            result = jedis.set(key, value);
            if (Constant.RedisPrefixConstant.OK.equals(result)) {
                jedis.expire(key, expiretime);
            }
            return result;
        } catch (Exception e) {
            throw new CustomException("设置Redis键值setJson方法异常:key=" + key + " value=" + value + " cause=" + e.getMessage());
        }
    }

    /**
     * 删除key
     * @param key
     * @return java.lang.Long
     * @author dog_E
     * @date 2018/9/4 15:50
     */
    public static Long delKey(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.del(key.getBytes());
        } catch (Exception e) {
            throw new CustomException("删除Redis的键delKey方法异常:key=" + key + " cause=" + e.getMessage());
        }
    }

    /**
     * 删除key
     * @param key
     * @return java.lang.Long
     * @author dog_E
     * @date 2018/9/4 15:50
     */
    public static Boolean delKeyBoolean(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * key是否存在
     * @param key
     * @return java.lang.Boolean
     * @author dog_E
     * @date 2018/9/4 15:51
     */
    public static Boolean exists(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.exists(key);
        } catch (Exception e) {
            throw new CustomException("查询Redis的键是否存在exists方法异常:key=" + key + " cause=" + e.getMessage());
        }
    }

    /**
     * 模糊查询获取key集合(keys的速度非常快，但在一个大的数据库中使用它仍然可能造成性能问题，生产不推荐使用)
     * @param key
     * @return java.util.Set<java.lang.String>
     * @author dog_E
     * @date 2018/9/6 9:43
     */
    public static Set<String> keysS(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.keys(key);
        } catch (Exception e) {
            throw new CustomException("模糊查询Redis的键集合keysS方法异常:key=" + key + " cause=" + e.getMessage());
        }
    }

    /**
     * 模糊查询获取key集合(keys的速度非常快，但在一个大的数据库中使用它仍然可能造成性能问题，生产不推荐使用)
     * @param key
     * @return java.util.Set<java.lang.String>
     * @author dog_E
     * @date 2018/9/6 9:43
     */
    public static Set<byte[]> keysB(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.keys(key.getBytes());
        } catch (Exception e) {
            throw new CustomException("模糊查询Redis的键集合keysB方法异常:key=" + key + " cause=" + e.getMessage());
        }
    }


    /**
     * redis做hash的添加
     */
    public static boolean hset(String key, String field, String value){
        if(SUtils.isBlank(key) || SUtils.isBlank(field)){
            return false;
        }
        try (Jedis jedis = jedisPool.getResource()) {
            //If the field already exists, and the HSET just produced an update of the value, 0 is returned,
            //otherwise if a new field is created 1 is returned.
            Long statusCode = jedis.hset(key, field, value);
            if(statusCode > -1){
                return true;
            }
        } catch (Exception e) {
            throw new CustomException("模糊查询Redis的键集合keysB方法异常:key=" + key + " cause=" + e.getMessage());
        }
        return false;
    }

    /**
     * @Description: 获取hsah中field的value
     * @Author: @Dog_Elder
     * @Date: 2020/11/18 14:09
     * @param key: key
     * @param field: map中key
     * @return: map中value
     **/
    public static String hget(String key, String field){
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hget(key, field);
        } catch (Exception e) {
            throw new CustomException("获取hsah中field的value方法异常:key=" + key + "field=" + field + " cause=" + e.getMessage());
        }
    }


    /**
     * @Description: hash 值 增或加
     * @Author: @Dog_Elder
     * @Date: 2020/11/19 14:35
     * @param key: key
     * @param field: map中key
     * @param value: 可以是正数 也可以是负数
     * @return: java.lang.Long
     **/
    public static Long hincrBy(String key, String field,long value){
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.hincrBy(key,field,value);
        } catch (Exception e) {
            throw new CustomException("获取hsah中field的value方法异常:key=" + key + "field=" + field + " cause=" + e.getMessage());
        }
    }


    /**
     * 获取过期剩余时间
     * @param key
     * @return java.lang.String
     * @author dog_E
     * @date 2018/9/11 16:26
     */
    public static Long ttl(String key) {
        Long result = -2L;
        try (Jedis jedis = jedisPool.getResource()) {
            result = jedis.ttl(key);
            return result;
        } catch (Exception e) {
            throw new CustomException("获取Redis键过期剩余时间ttl方法异常:key=" + key + " cause=" + e.getMessage());
        }
    }




    //TODO 以下是分布式锁中的内容

//    public static String get(String key){
//        Jedis jedis = null;
//        String result = null;
//        try {
//            jedis = jedisPool.getResource();
//            result = jedis.get(key);
//        } catch (Exception e){
//            e.printStackTrace();
//        } finally {
//            if (jedis != null) {
//                jedis.close();
//            }
//            return result;
//        }
//    }
//
//    public static Long setnx(String key, String value){
//        Jedis jedis = null;
//        Long result = null;
//        try {
//            jedis = jedisPool.getResource();
//            result = jedis.setnx(key, value);
//        } catch (Exception e){
//            e.printStackTrace();
//        } finally {
//            if (jedis != null) {
//                jedis.close();
//            }
//            return result;
//        }
//    }
//
//    public static String getSet(String key, String value){
//        Jedis jedis = null;
//        String result = null;
//        try {
//            jedis = jedisPool.getResource();
//            result = jedis.getSet(key, value);
//        } catch (Exception e){
//            e.printStackTrace();
//        } finally {
//            if (jedis != null) {
//                jedis.close();
//            }
//            return result;
//        }
//    }
//
//    public static Long expire(String key, int seconds){
//        Jedis jedis = null;
//        Long result = null;
//        try {
//            jedis = jedisPool.getResource();
//            result = jedis.expire(key, seconds);
//        } catch (Exception e){
//            e.printStackTrace();
//        } finally {
//            if (jedis != null) {
//                jedis.close();
//            }
//            return result;
//        }
//    }
//
//    public static Long del(String key){
//        Jedis jedis = null;
//        Long result = null;
//        try {
//            jedis = jedisPool.getResource();
//            result = jedis.del(key);
//        } catch (Exception e){
//            e.printStackTrace();
//        } finally {
//            if (jedis != null) {
//                jedis.close();
//            }
//            return result;
//        }
//    }
//
//    /**
//     * 尝试获取分布式锁
//     * @param jedis Redis客户端
//     * @param lockKey 锁
//     * @param requestId 请求标识
//     * @param expireTime 超期时间
//     * @return 是否获取成功
//     */
//    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
//        String result = jedis.set(lockKey, requestId, Constant.SET_IF_NOT_EXIST, Constant.SET_WITH_EXPIRE_TIME, expireTime);
//        if (Constant.LOCK_SUCCESS.equals(result)) {
//            return true;
//        }
//        return false;
//
//    }

//    /**
//     * 释放分布式锁
//     * @param jedis Redis客户端
//     * @param lockKey 锁
//     * @param requestId 请求标识
//     * @return 是否释放成功
//     */
//    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {
//        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
//        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
//        if (Constant.RELEASE_SUCCESS.equals(result)) {
//            return true;
//        }
//        return false;
//    }


}
